package common.generate.config.generate.config;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.ConstVal;
import com.baomidou.mybatisplus.generator.config.FileOutConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.TemplateConfig;
import com.baomidou.mybatisplus.generator.config.builder.ConfigBuilder;
import com.baomidou.mybatisplus.generator.config.po.TableField;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.FileType;
import com.baomidou.mybatisplus.generator.engine.AbstractTemplateEngine;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import common.generate.config.generate.Generate;
import common.util.base.CommonUtil;
import common.util.base.CustomizeRuntimeException;

import java.io.File;
import java.text.SimpleDateFormat;
import java.util.*;


public class MyFreemarkerTemplateEngine extends FreemarkerTemplateEngine{
	
	@Override
	public AbstractTemplateEngine batchOutput() {
        try {
        	MyGenerateConfig config = Generate.config;
            List<TableInfo> tableInfoList = getConfigBuilder().getTableInfoList();
            for (TableInfo tableInfo : tableInfoList) {
                Map<String, Object> objectMap = getObjectMap(tableInfo);
                Map<String, String> pathInfo = getConfigBuilder().getPathInfo();
                TemplateConfig template = getConfigBuilder().getTemplate();
                // 自定义内容
                InjectionConfig injectionConfig = getConfigBuilder().getInjectionConfig();
                if (null != injectionConfig) {
                    injectionConfig.initMap();
                    objectMap.put("cfg", injectionConfig.getMap());
                    List<FileOutConfig> focList = injectionConfig.getFileOutConfigList();
                    if (CollectionUtils.isNotEmpty(focList)) {
                        for (FileOutConfig foc : focList) {
                        	if(!config.getDaoCreate()) {
                        		if(foc.getTemplatePath().endsWith("dao.java.ftl")) {
                        			continue;
                        		}
                        	}
                        	if(!config.getDaoImplCreate()) {
                        		if(foc.getTemplatePath().endsWith("daoImpl.java.ftl")) {
                        			continue;
                        		}
                        	}
                        	if(!config.getEntityEmeusCreate()) {
                        		if(foc.getTemplatePath().endsWith("emeu.java.ftl")) {
                        			continue;
                        		}
                        	}
                        	if(!config.getFeignCreate()){
                        	    if(foc.getTemplatePath().endsWith("feign.java.ftl")) {
                                    continue;
                                }
                            }
                        	if(!config.getFeignFallbackCreate()){
                        	    if(foc.getTemplatePath().endsWith("feignFallback.java.ftl")) {
                        	        continue;
                                }
                            }
                            if(!config.getEditJsCreate()){
                                if(foc.getTemplatePath().endsWith("edit.js.ftl")) {
                                    continue;
                                }
                            }
                            if(!config.getEditHtmlCreate()){
                                if(foc.getTemplatePath().endsWith("edit.html.ftl")) {
                                    continue;
                                }
                            }
                            if(!config.getListJsCreate()){
                                if(foc.getTemplatePath().endsWith("list.js.ftl")) {
                                    continue;
                                }
                            }
                            if(!config.getListHtmlCreate()){
                                if(foc.getTemplatePath().endsWith("list.html.ftl")) {
                                    continue;
                                }
                            }
                            if (isCreate(FileType.OTHER, foc.outputFile(tableInfo))) {
                            	String filePath = foc.outputFile(tableInfo);
                            	if(foc.getTemplatePath().endsWith("emeu.java.ftl")&& new File(filePath).exists()) {
                            		filePath=filePath+".bak";
                        		}
                                writer(objectMap, foc.getTemplatePath(), filePath);
                            }

                        }
                    }
                }
                // Mp.java
                String entityName = tableInfo.getEntityName();
                if (null != entityName && null != pathInfo.get(ConstVal.ENTITY_PATH)) {
                    String entityFile = String.format((pathInfo.get(ConstVal.ENTITY_PATH) + File.separator + "%s" + suffixJavaOrKt()), entityName);
                    if (isCreate(FileType.ENTITY, entityFile)) {
                    	if(config.getEntityCreate()) {
                    		writer(objectMap, templateFilePath(template.getEntity(getConfigBuilder().getGlobalConfig().isKotlin())), entityFile);
                    	}
                    }
                }
                // MpMapper.java
                if (null != tableInfo.getMapperName() && null != pathInfo.get(ConstVal.MAPPER_PATH)) {
                    String mapperFile = String.format((pathInfo.get(ConstVal.MAPPER_PATH) + File.separator + tableInfo.getMapperName() + suffixJavaOrKt()), entityName);
                    if (isCreate(FileType.MAPPER, mapperFile)) {
                    	if(config.getMapperCreate()) {
                    		writer(objectMap, templateFilePath(template.getMapper()), mapperFile);
                    	}
                    }
                }
                // MpMapper.xml
                if (null != tableInfo.getXmlName() && null != pathInfo.get(ConstVal.XML_PATH)) {
                    String xmlFile = String.format((pathInfo.get(ConstVal.XML_PATH) + File.separator + tableInfo.getXmlName() + ConstVal.XML_SUFFIX), entityName);
                    if (isCreate(FileType.XML, xmlFile)) {
                    	if(config.getXmlMapperCreate()) {
                    		writer(objectMap, templateFilePath(template.getXml()), xmlFile);
                    	}
                    }
                }
                // IMpService.java
                if (null != tableInfo.getServiceName() && null != pathInfo.get(ConstVal.SERVICE_PATH)) {
                    String serviceFile = String.format((pathInfo.get(ConstVal.SERVICE_PATH) + File.separator + tableInfo.getServiceName() + suffixJavaOrKt()), entityName);
                    if (isCreate(FileType.SERVICE, serviceFile)) {
                    	if(config.getServiceCreate()) {
                    		writer(objectMap, templateFilePath(template.getService()), serviceFile);
                    	}
                    }
                }
                // MpServiceImpl.java
                if (null != tableInfo.getServiceImplName() && null != pathInfo.get(ConstVal.SERVICE_IMPL_PATH)) {
                    String implFile = String.format((pathInfo.get(ConstVal.SERVICE_IMPL_PATH) + File.separator + tableInfo.getServiceImplName() + suffixJavaOrKt()), entityName);
                    if (isCreate(FileType.SERVICE_IMPL, implFile)) {
                    	if(config.getServiceImplCreate()) {
                    		writer(objectMap, templateFilePath(template.getServiceImpl()), implFile);
                    	}
                    }
                }
                // MpController.java
                if (null != tableInfo.getControllerName() && null != pathInfo.get(ConstVal.CONTROLLER_PATH)) {
                    String controllerFile = String.format((pathInfo.get(ConstVal.CONTROLLER_PATH) + File.separator + tableInfo.getControllerName() + suffixJavaOrKt()), entityName);
                    if (isCreate(FileType.CONTROLLER, controllerFile)) {
                    	if(config.getControllerCreate()) {
                    		writer(objectMap, templateFilePath(template.getController()), controllerFile);
                    	}
                    }
                }
            }
        } catch (Exception e) {
            logger.error("无法创建文件，请检查配置信息！", e);
        }
        return this;
    }
	
	@SuppressWarnings("unchecked")
	@Override
	public Map<String, Object> getObjectMap(TableInfo tableInfo) {
        Map<String, Object> objectMap = new HashMap<>();
        ConfigBuilder config = getConfigBuilder();
        if (config.getStrategyConfig().isControllerMappingHyphenStyle()) {
            objectMap.put("controllerMappingHyphenStyle", config.getStrategyConfig().isControllerMappingHyphenStyle());
            objectMap.put("controllerMappingHyphen", StringUtils.camelToUnderline(tableInfo.getEntityPath()));
        }
        objectMap.put("restControllerStyle", config.getStrategyConfig().isRestControllerStyle());
        objectMap.put("config", config);
        objectMap.put("package", config.getPackageInfo());
        GlobalConfig globalConfig = config.getGlobalConfig();
        objectMap.put("author", globalConfig.getAuthor());
        objectMap.put("idType", globalConfig.getIdType() == null ? null : globalConfig.getIdType().toString());
        objectMap.put("logicDeleteFieldName", config.getStrategyConfig().getLogicDeleteFieldName());
        objectMap.put("versionFieldName", config.getStrategyConfig().getVersionFieldName());
        objectMap.put("activeRecord", globalConfig.isActiveRecord());
        objectMap.put("kotlin", globalConfig.isKotlin());
        objectMap.put("swagger2", globalConfig.isSwagger2());
        objectMap.put("date", new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
        objectMap.put("table", tableInfo);
        objectMap.put("emeus", false);
        objectMap.put("projectName",Generate.projectName);
        List<Map<String,Object>> fields = new ArrayList<Map<String,Object>>();
		for(TableField field:tableInfo.getFields()){
			Map<String, Object> map = CommonUtil.convertBeanToMap(field);
			String fieldName = field.getPropertyName().substring(0, 1).toUpperCase()+field.getPropertyName().substring(1);
			map.put("upperPropertyName", fieldName);
			String comment = (String) map.get("comment");
            map.put("commentShow",comment);
			List<Map<String,Object>> fieldDesc = (List<Map<String, Object>>) map.get("fieldDesc");
			if(CommonUtil.isNotEmpty(comment)){
				int first = comment.indexOf("[");
				int end = comment.indexOf("]");
				if(first >-1 && end > -1 && end -first >3 ){
                    map.put("commentShow", comment.substring(0,first));
					String str = comment.substring(first+1,end);
					String[] one = str.split(",");
					if(CommonUtil.isEmpty(fieldDesc)){
						fieldDesc = new ArrayList<>();
					}
					for(String two:one){
						String[] three = two.split(":");
						if(three.length != 2){
							throw new CustomizeRuntimeException("错误的格式,格式支持 [字段值:值描述,字段值:值描述....]");
						}
						Map<String,Object> descMap = new HashMap<>();
						descMap.put("key", three[0]);
						descMap.put("desc", three[1]);
						descMap.put("pinyin", CommonUtil.getPinYin(three[1]));
						map.put("descComment", comment.substring(0,first));
						fieldDesc.add(descMap);
						objectMap.put("emeus", true);
					}
					if(CommonUtil.isEmpty(fieldDesc)){
						fieldDesc = null;
					}
				}
				
			}
			map.put("fieldDesc", fieldDesc);

			int begin = field.getType().indexOf("(");
			int end= field.getType().indexOf(")")+1;
			if( end == 0){
			    end = field.getType().length();
            }
			if(begin>-1 && end >-1){
				String[] lengths = field.getType().substring(begin+1,end-1).split(",");
				if(lengths.length==1){
					map.put("maxLength", Integer.valueOf(lengths[0]));
					map.put("decimalLength", 0);
				}else if(lengths.length==2){

					map.put("maxLength", Integer.valueOf(lengths[0]));
					map.put("decimalLength", Integer.valueOf(lengths[1]));
				}else{
					throw new CustomizeRuntimeException("位置的数据类型[type]:"+CommonUtil.convertObjectToJson(field));
				}
			}
			fields.add(map);
		}
		objectMap.put("fields", fields);
		
        objectMap.put("enableCache", globalConfig.isEnableCache());
        objectMap.put("baseResultMap", globalConfig.isBaseResultMap());
        objectMap.put("baseColumnList", globalConfig.isBaseColumnList());
        objectMap.put("entity", tableInfo.getEntityName());
        objectMap.put("entitySerialVersionUID", config.getStrategyConfig().isEntitySerialVersionUID());
        objectMap.put("entityColumnConstant", config.getStrategyConfig().isEntityColumnConstant());
        objectMap.put("entityBuilderModel", config.getStrategyConfig().isEntityBuilderModel());
        objectMap.put("entityLombokModel", config.getStrategyConfig().isEntityLombokModel());
        objectMap.put("entityBooleanColumnRemoveIsPrefix", config.getStrategyConfig().isEntityBooleanColumnRemoveIsPrefix());
        objectMap.put("superEntityClass", getSuperClassName(config.getSuperEntityClass()));
        objectMap.put("superMapperClassPackage", config.getSuperMapperClass());
        objectMap.put("superMapperClass", getSuperClassName(config.getSuperMapperClass()));
        objectMap.put("superServiceClassPackage", config.getSuperServiceClass());
        objectMap.put("superServiceClass", getSuperClassName(config.getSuperServiceClass()));
        objectMap.put("superServiceImplClassPackage", config.getSuperServiceImplClass());
        objectMap.put("superServiceImplClass", getSuperClassName(config.getSuperServiceImplClass()));
        objectMap.put("superControllerClassPackage", config.getSuperControllerClass());
        objectMap.put("superControllerClass", getSuperClassName(config.getSuperControllerClass()));
        return objectMap;
    }
    /**
     * 获取类名
     *
     * @param classPath ignore
     * @return ignore
     */
    private String getSuperClassName(String classPath) {
        if (StringUtils.isEmpty(classPath)) {
            return null;
        }
        return classPath.substring(classPath.lastIndexOf(StringPool.DOT) + 1);
    }
}
